package com.schmix.dpp;

import java.io.IOException;
import java.util.List;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;

public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {

	protected boolean circleShape = true;
	public static final String TAG = "CameraPreview";
	private Camera camera;
	private SurfaceView view;
	private SurfaceHolder holder;
	private Size previewSize;
	private List<Size> supportedPreviewSizes;

	public CameraPreview(Context context) {
		super(context);
		init();
	}
	
	public CameraPreview(Context context, AttributeSet attrs){
		super(context, attrs);
		init();
	}
	
	private void init(){
		view = new SurfaceView(getContext());
		holder = view.getHolder();
		holder.addCallback(this);
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		cameraInit();
	}
	
	private void cameraInit(){
		camera = Camera.open();
		if (null != camera) {
            supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
            requestLayout();
        }

	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(previewSize.width, previewSize.height);
        requestLayout();

        camera.setParameters(parameters);
        camera.startPreview();
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (null == camera) {
			// TODO: No back facing camera, figure something out.
		}
		try {
			camera.setPreviewDisplay(holder);
		} catch (IOException e) {
			Log.e(TAG, e.getClass().getName() + ": " + e.getMessage());
			// TODO: display an error message, have the dismissal dispose of
			// the activity
		}
	}
	
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		destroyCamera();
	}
	
	@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes(); 
        
        if (null != supportedPreviewSizes) {
            previewSize = getOptimalPreviewSize(supportedPreviewSizes, width, height);
        }
    }

	protected void destroyCamera() {
		camera.release();
		camera = null;
	}
	
	public void pause(){
		if (null != camera){
			camera.release();
			camera = null;
		}
	}
	
	public void resume(){
		cameraInit();
	}
	
	private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = right - left;
            final int height = bottom - top;

            int previewWidth = width;
            int previewHeight = height;
            if (previewSize != null) {
                previewWidth = previewSize.width;
                previewHeight = previewSize.height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                        (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2,
                        width, (height + scaledChildHeight) / 2);
            }
        }

	}

	
}
